function  THhUtilsClient() {
    this.config={
        apiUrl :"https://wss.hhdata.cn:20021/apikms10" ,
        wsUrl:"wss://wss.hhdata.cn:20021/kmsv10" ,
        kurentUrl:"wss://wss.hhdata.cn:8433/kurento",
        defaultPeerOptions:{
            configuration: {
                "iceServers":[
                    {
                        urls:"stun:223.68.161.139:3478"
                    },
                    {
                        urls:["turn:223.68.161.139:3478"],
                        username:"kurento",
                        credential: "kurento"
                    }
                ]
            },
            mediaConstraints:{
               audio: true,
               video: {width: {exact: 1280}, height: {exact: 720}}
            },
            localVideo: null ,
            remoteVideo: null
        }
    };
    this.kurentClient = null;
    this.ws= null;
    this.kmsDict={};
    this.kmsPeerTypes={
        send:kurentoUtils.WebRtcPeer.WebRtcPeerSendonly,
        rec:kurentoUtils.WebRtcPeer.WebRtcPeerRecvonly,
        sendRec:kurentoUtils.WebRtcPeer.WebRtcPeerSendrecv
    };
    this.callBack = function (callback , ps0 , ps1 ,ps2) {
        try {
            if (callback) {
                callback(ps0,ps1,ps2);
            }
        }
        catch (e) {
            ;
        }
    }
}
THhUtilsClient.prototype.callApi = function (ac , data , callback) {
    var me = this;
    try{

        var aUrl = me.config.apiUrl+"/"+ac+"?tm="+( new Date()).getTime().toString();
        $.ajax({
            url: aUrl ,
            data : data ,
            type:"POST",
            success: function (resData) {
                try{
                    var res = JSON.parse(resData);
                    me.callBack(callback , res);
                }
                catch (erSuccess) {
                    console.log(erSuccess);
                }
            },
            error: function (er0, er1  ) {
                try{
                    me.callBack(callback , {er0:er0 , er1:er1});
                }
                catch (erSuccess) {
                    console.log(erSuccess);
                }
            }
        })
    }
    catch (e) {
        console.log("rtcClient.callApi error.", e);
    }
};
THhUtilsClient.prototype.dbQuery = function (appName , key , ps , callback) {
    var me = this;
    try{
        var data ={
            app:appName ,
            key: key ,
            psJson:JSON.stringify(ps)
        };
        var ac ="queryArray";
        me.callApi(ac , data , callback);

    }
    catch (e) {
        console.log("rtcClient.callApi error.", e);
    }
};
THhUtilsClient.prototype.kmsGetClient = function( callback){
    var me = this;
    try{
        if (me.kurentClient){
            me.callBack(callback, me.kurentClient );
        }
        else {
            kurentoClient(me.config.kurentUrl, function (error, client) {
                if (client) {
                    me.kurentClient = client;
                }
                me.callBack(callback, client);
            });
        }
    }
    catch (er) {
        console.log(er);
    }
};
THhUtilsClient.prototype.kmsBindPeerAndEndpoint = function ( peer , endpoint,  callback) {
    var me = this;
    try{
        var setCandidateEvent = function( peer , endpoint   ) {
            try {
                if (peer && endpoint) {
                    endpoint.on('OnIceCandidate', function (event) {
                        var candidate = event.candidate;
                        peer.addIceCandidate(candidate);
                        console.log('candidate w->p')
                    });
                    peer.on('icecandidate', function (candidate) {
                        var iceCandidate = kurentoClient.register.complexTypes.IceCandidate(candidate);
                        endpoint.addIceCandidate(iceCandidate);
                        console.log('candidate p->w')

                    });
                }
            }
            catch (e) {
                ;
            }
        }
        if( endpoint && peer){
            peer.generateOffer(function (errorPeerGenerateOffer, sdpOffer) {
                if( errorPeerGenerateOffer && callback){
                    callback( errorPeerGenerateOffer , null);
                }
                else {
                    endpoint.processOffer(sdpOffer, function (errorSdpOffer, sdpAnswer) {
                        if (errorSdpOffer && callback) {
                            console.log("process sdpOffer error.", errorSdpOffer)
                            callback(errorSdpOffer, null);
                        } else {
                            setCandidateEvent(peer , endpoint);
                            peer.processAnswer(sdpAnswer);
                            endpoint.gatherCandidates(function (errorGatherCandidates) {
                                if (errorGatherCandidates && callback) {
                                    console.log('webRtcPoint gatherCandidates error.', errorGatherCandidates)
                                    callback(errorGatherCandidates, null);
                                }
                                else{
                                    peer.endpoint = endpoint;
                                    endpoint.peer = peer;
                                    setCandidateEvent(peer , endpoint);
                                    if( callback) {
                                        callback(null, {endpoint: endpoint, peer: peer});
                                    }
                                }
                            });
                        }
                    });
                }
            });
        }
        else {
            if( callback) {
                callback({ error:"endPoint or peer is null."}, null);
            }
        }
    }
    catch (er) {
        console.log(er,"bindPeerAndEndpoint error.");
    }
};
THhUtilsClient.prototype.kmsGetAvDevices = function ( callback) {
    var me = this;
    try{
        var res ={};
/*
        navigator.mediaDevices.enumerateDevices(function (devs) {

            for( var i=0;i<devs.length;i++){
                var item = devs[i];
                if( !res[item.kind]){
                    res[item.kind]=[]
                }
                res[item.kind].push(item);
            }
            console.log(res);
            if (callback){
                callback({error: null, devices:res});
            }
        });
*/
        navigator.mediaDevices.enumerateDevices().then(function (devs) {
            for( var i=0;i<devs.length;i++){
                var item = devs[i];
                if( !res[item.kind]){
                    res[item.kind]=[]
                }
                res[item.kind].push(item);
            }
            console.log(res);
            if (callback){
                callback({error: null, devices:res});
            }
        });
    }
    catch (er) {
        console.log(er,"createPeer error.");
    }
};
THhUtilsClient.prototype.kmsChangeCamera = function ( peer, newCameraDeviceId , callback) {
    var me = this;
    try{
        var result={error:null , res: null}
        //var constraints = {video: {deviceId: {exact: newCameraDeviceId}}};
        var constraints = {video: {deviceId: newCameraDeviceId}};
        var sender = null;
        navigator.mediaDevices.getUserMedia(constraints).then(function (stream) {
            try{
                if( stream){
                    let videoTrack = stream.getVideoTracks()[0];
                    peer.localVideo.srcObject = stream;
                    sender = peer.peerConnection.getSenders().find(function (s) {
                        return s.track.kind == videoTrack.kind;
                    });
                    sender.track.stop();
                    sender.replaceTrack(videoTrack);
                    result.res = constraints;
                    if( callback){
                        callback(result);
                    }
                }
                else{
                    if( callback){
                        result.error = "stream is null";
                        callback(result);
                    }
                }
            }
            catch (er) {
                console.log(er);
            }
        });
    }
    catch (er) {
        console.log(er);
    }
}
THhUtilsClient.prototype.kmsShareScreen = function ( peer , callback) {
    var me = this;
    try{
        var screenConstraints={video:{width:{max:1280}, height:{max:720}} , audio:true};
        if (navigator.mediaDevices.getDisplayMedia) {
            //navigator.mediaDevices.getDisplayMedia({video:true}).then(
            navigator.mediaDevices.getDisplayMedia(screenConstraints).then(
                function (stream) {
                    let videoTrack = stream.getVideoTracks()[0];
                    peer.localVideo.srcObject = stream;
                    sender = peer.peerConnection.getSenders().find( function (s) {
                        return s.track.kind == videoTrack.kind;
                    });
                    sender.track.stop();
                    sender.replaceTrack(videoTrack);
                    if( callback) {
                        callback( );
                    }
                }
            )
        }
    }
    catch (er) {
        console.log(er);
    }
}
THhUtilsClient.prototype.openWs = function( onOpen , onClose , onMsg ){
    var me = this;
    try{
        var ws = new WebSocket(me.config.wsUrl);
        ws.onopen = function(){
        　　//当WebSocket创建成功时，触发onopen事件
           console.log("wss is openned!");
        };
        ws.onerror = function(){
        　　try{
                ws.close();
            }
            catch (e1) {
                console.log(e1);
            }
        };
        ws.onclose = function(){
        　　try{
                me.callBack(onClose, ws);
            }
            catch (e1) {
                console.log(e1);
            }
        };
        ws.onmessage = function(e){
        　　//当客户端收到服务端发来的消息时，触发onmessage事件，参数e.data包含server传递过来的数据
        　　console.log(e.data);
            try{
                var msg = JSON.parse(e.data);
                if( msg.msgId == "onGetWsId" ){
                    ws.wsId = msg.msgBody.wsId;
                    me.callBack(onOpen, ws);
                }
                else  if( onMsg){
                    me.callBack(onMsg , ws, msg);
                }
            }
            catch (err) {
                console.log(err);
            }
        };
        me.ws = ws;
    }
    catch (er) {
        console.log(er);
    }
};